home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / misc / unix / tracker_4_3.lzh / tracker / Amiga / client.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-13  |  7.2 KB  |  314 lines

  1. /* amiga/client.c 
  2.     vi:se ts=3 sw=3:
  3.  */
  4.  
  5. /* $Id: client.c,v 1.8 1994/01/09 17:38:28 Espie Exp Espie $
  6.  * $Log: client.c,v $
  7.  * Revision 1.8  1994/01/09  17:38:28  Espie
  8.  * Generalized open.c.
  9.  *
  10.  * Revision 1.7  1994/01/08  19:45:29  Espie
  11.  * Uncentralized event handling using event management functions.
  12.  *
  13.  * Revision 1.6  1994/01/08  04:00:52  Espie
  14.  * Priority lowered.
  15.  *
  16.  * Revision 1.5  1994/01/07  15:57:20  Espie
  17.  * Added check_type call for non-blocking processing.
  18.  *
  19.  * Revision 1.4  1994/01/07  15:08:54  Espie
  20.  * Id.
  21.  *
  22.  * Revision 1.3  1994/01/06  22:37:26  Espie
  23.  * *** empty log message ***
  24.  *
  25.  * Revision 1.2  1994/01/05  19:24:08  Espie
  26.  * Fully working asynchronous interface.
  27.  *
  28.  * Revision 1.1  1994/01/05  16:48:58  Espie
  29.  * Initial revision
  30.  *
  31.  */
  32.  
  33. /* client to the audio server */
  34.  
  35.  
  36. #include <exec/types.h>
  37. #include <exec/tasks.h>
  38. #include <exec/memory.h>
  39. #include <exec/ports.h>
  40.  
  41. #include <proto/exec.h>
  42.  
  43. #include <stdio.h>
  44.  
  45. #include "defs.h"
  46. #include "extern.h"
  47. #include "song.h"
  48. #include "amiga/amiga.h"
  49.  
  50. ID("$Id: client.c,v 1.8 1994/01/09 17:38:28 Espie Exp Espie $")
  51. XT unsigned int inhibit_output;
  52.  
  53. LOCAL void init_client(void);
  54. LOCAL void (*INIT)(void) = init_client;
  55.  
  56. #define STACK_SIZE 4000
  57. #define HIPRI 50     /* should be higher than intuition's */
  58. #define SUBNAME "Tracker sound server"
  59.  
  60. LOCAL struct MsgPort *subport = 0;
  61.  
  62. LOCAL struct MsgPort *myport = 0;
  63.  
  64. LOCAL struct ext_message *chunk = 0;
  65.  
  66. LOCAL struct MinList buffer;
  67. LOCAL boolean live_task = FALSE;
  68. LOCAL int watched_type = TYPE_INVALID; 
  69. LOCAL struct ext_message *watched_message;
  70.  
  71. LOCAL void handle_subtask_events(GENERIC nothing)
  72.    {
  73.    struct ext_message *msg;
  74.    
  75.    while (msg = GetMsg(myport))
  76.       {
  77.       if (msg->type == TYPE_SYNC_DO)
  78.          (msg->data.hook.func)(msg->data.hook.p);
  79.       AddTail(&buffer, msg);
  80.       if (msg->type == watched_type)
  81.          {
  82.          watched_message = msg;
  83.          watched_type = TYPE_INVALID;
  84.          }
  85.       }
  86.    }
  87.  
  88. struct ext_message *obtain_message()
  89.    {
  90.    struct ext_message *msg;
  91.    
  92.    INIT_ONCE;
  93.  
  94.    forever
  95.       {
  96.          /* get messages from port first: best synchronization */
  97.       check_events();
  98.             /* message available ? */
  99.       if (msg = RemHead(&buffer))
  100.          return msg;
  101.       else  /* no-> wait for one */
  102.          await_events();
  103.       }
  104.    }
  105.  
  106.  
  107. void send(struct ext_message *msg, int type)
  108.    {
  109.       /* valid only for messages obtained through obtain_message ! */
  110.    msg->type = type;
  111.    msg->msg.mn_ReplyPort = myport;
  112.    PutMsg(subport, msg);
  113.    }
  114.  
  115.  
  116. struct ext_message *check_type(int type)
  117.    {
  118.    struct ext_message *msg;
  119.  
  120.    watched_type = type;
  121.    check_events();
  122.    if (watched_message)
  123.       {
  124.       msg = watched_message;
  125.       watched_message = 0;
  126.       return msg;
  127.       }
  128.    else
  129.       return 0;
  130.    }
  131.    
  132. /* Note that await_type returns a message for checking purposes.
  133.  * This message is NOT available
  134.  */
  135. struct ext_message *await_type(int type)
  136.    {
  137.    struct ext_message *msg;
  138.  
  139.    forever
  140.       {
  141.       watched_type = type;
  142.       check_events();
  143.       if (watched_message)
  144.          {
  145.          msg = watched_message;
  146.          watched_message = 0;
  147.          return msg;
  148.          }
  149.       await_events();
  150.       }
  151.    }
  152.  
  153. LOCAL void kill_subtask()
  154.    {
  155.    struct ext_message *msg;
  156.       /* tell the subtask to die */
  157.    msg = obtain_message();
  158.    send(msg, TYPE_DIE);
  159.       /* and wait for it to be in a dying state (Wait(0)) */
  160.    msg = await_type(TYPE_DIE);
  161. #ifndef EXTERNAL
  162.       /* then kill it */
  163.    RemTask(msg->data.comm.task);
  164. #endif
  165.    live_task = FALSE;
  166.    }
  167.  
  168.  
  169.  
  170. LOCAL struct Task *newtask = 0;
  171. LOCAL void *stack = 0;
  172.  
  173. /* We build up the task structure by ourselves. That way, we can
  174.  * easily pass a message around by pushing it on the stack
  175.  */
  176. LOCAL void create_subtask()
  177.    {
  178.    ULONG *p;
  179.    struct ext_message *msg;
  180.  
  181. #ifdef EXTERNAL
  182.       /* we just have to find the task */
  183.    struct MsgPort *pubport;
  184.  
  185.    pubport = FindPort(PUBLIC_PORT_NAME);
  186.    if (!pubport)
  187.       end_all("Could not rendez-vous");
  188.       /* it's there: get it in working order */
  189.    msg = obtain_message();
  190.    msg->type = TYPE_COMM;
  191.    msg->msg.mn_ReplyPort = myport;
  192.    PutMsg(pubport, msg);
  193.    msg = await_type(TYPE_COMM);
  194.       /* check it's running correctly */
  195.    if (msg->data.comm.port)
  196.       {
  197.       subport = msg->data.comm.port;
  198.       live_task = TRUE;
  199.       }
  200.    else
  201.       {
  202.       end_all("subtask creation failed");
  203.       }
  204. #else
  205.       /* build the new task from scratch */
  206.    newtask = AllocVec(sizeof(struct Task), MEMF_CLEAR | MEMF_PUBLIC);
  207.    if (!newtask)
  208.       end_all("No task struct");
  209.    stack = AllocVec(STACK_SIZE, MEMF_CLEAR);
  210.    if (!stack)
  211.       end_all("No stack");
  212.    newtask->tc_SPLower = stack;
  213.    newtask->tc_SPUpper = (APTR)((ULONG)(newtask->tc_SPLower) + STACK_SIZE);
  214.    newtask->tc_Node.ln_Type = NT_TASK;
  215.    newtask->tc_Node.ln_Pri = HIPRI;
  216.    newtask->tc_Node.ln_Name = SUBNAME;
  217.  
  218.       /* ready to run: set it up for answering */      
  219.    msg = obtain_message();
  220.    msg->type = TYPE_COMM;
  221.    msg->msg.mn_ReplyPort = myport;
  222.       /* push message on the stack */
  223.    p = newtask->tc_SPUpper;
  224.    *(--p) = (ULONG)msg;
  225.    newtask->tc_SPReg = p;
  226.    
  227.    if (!AddTask(newtask, subtask, 0))
  228.       end_all("No subtask");
  229.       /* Check it started up okay */
  230.    msg = await_type(TYPE_COMM);
  231.    if (msg->data.comm.port)
  232.       {
  233.       subport = msg->data.comm.port;
  234.       live_task = TRUE;
  235.       }
  236.    else
  237.       {
  238.       RemTask(msg->data.comm.task);
  239.       end_all("subtask creation failed");
  240.       }
  241. #endif
  242.    }
  243.  
  244.  
  245. /* right now, messages are statically allocated.
  246.  * It might be a good idea to start with a SMALL
  247.  * fixed number of messages (say 50) and increase
  248.  * the queue on timing faults. A bit tricky, though.
  249.  */
  250. LOCAL void alloc_messages()
  251.    {
  252.    int i;
  253.    
  254.    myport = CreateMsgPort();
  255.    if (!myport)
  256.       end_all("Couldn't open message port");
  257.    install_signal_handler(myport->mp_SigBit, handle_subtask_events, 0);
  258.    chunk = AllocVec(sizeof(struct ext_message) * BUFFER_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
  259.    if (!chunk)
  260.       end_all("Message allocation failed");
  261.    for (i = 0; i < BUFFER_SIZE; i++)
  262.       {
  263.          /* don't forget this ! */
  264.       chunk[i].msg.mn_Node.ln_Type = NT_MESSAGE;
  265.       chunk[i].msg.mn_Length = sizeof(struct ext_message);
  266.       AddTail(&buffer, chunk+i);
  267.       }
  268.    }
  269.  
  270. LOCAL void end_client()
  271.    {
  272.    if (live_task)
  273.       kill_subtask();
  274.       /* note that the subtask is already dead when end_client is called */
  275.    if (chunk)
  276.       FreeVec(chunk);
  277.    if (newtask)
  278.       FreeVec(newtask);
  279.    if (stack)
  280.       FreeVec(stack);
  281.    if (myport)
  282.       {
  283.       remove_signal_handler(myport->mp_SigBit);
  284.       DeleteMsgPort(myport);
  285.       }
  286.    }
  287.       
  288. LOCAL void init_client()
  289.    {
  290.    NewList(&buffer);
  291.    at_end(end_client);
  292.    alloc_messages();    /* note we must call alloc_messages BEFORE create_subtask
  293.                          * since create_subtask depends on obtain_message
  294.                          */
  295.    create_subtask();    /* this hooks kill_subtask, AFTER end_client,
  296.                          * so it will be called BEFORE.
  297.                          */
  298.    }
  299.  
  300. void close_audio(void)
  301.    {
  302.    if (live_task)
  303.       {
  304.       struct ext_message *msg;
  305.  
  306.       msg = obtain_message();
  307.       msg->data.info.channel_mask = 15;
  308.       send(msg, TYPE_FLUSH_CHANNEL);
  309.       while (msg != await_type(TYPE_FLUSH_CHANNEL))
  310.          ;
  311.       }
  312.    }
  313.  
  314.